//
//  BKHttpRequestQueue.m
//  Pods
//
//  Created by baboy on 1/18/16.
//
//

#import "BKHttpRequestQueue.h"
#import "NSString+x.h"
#import "BKKit.h"

@implementation BKHttpRequestTask
@end

@interface BKHttpRequestPool(){
    NSMutableDictionary *_pool;
}
@property(nonatomic, strong) dispatch_queue_t taskQueue;
@end
@implementation BKHttpRequestPool
+ (id)defaultPool {
    static id _pool = nil;
    static dispatch_once_t initOncePool;
    dispatch_once(&initOncePool, ^{
        _pool = [[BKHttpRequestPool alloc] init];
    });
    return _pool;
}
- (id)init{
    if (self = [super init]) {
        _pool = [NSMutableDictionary dictionary];
        NSString *taskQueueName = [NSString stringWithFormat:@"%@-BKHttpRequestPool-%@",APP_ID, [[NSUUID UUID] UUIDString]];
        self.taskQueue = dispatch_queue_create([taskQueueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_SERIAL);
    }
    return self;
}

- (void)addSessionTask:(NSURLSessionTask *)sessionTask withResponseHandler:(BKHttpResponseHandler *)responseHandler{
    dispatch_sync(self.taskQueue, ^{
       BKHttpRequestTask *task = [_pool valueForKey:responseHandler.taskId];
        if (task) {
            responseHandler.sessionTask = sessionTask;
            [task.responseHandlers addObject:responseHandler];
            return;
        }
        task = [[BKHttpRequestTask alloc] init];
        task.taskId = responseHandler.taskId;
        task.sessionTask = sessionTask;
        task.responseHandlers = [NSMutableArray array];
        [_pool setObject:task forKey:responseHandler.taskId];

        responseHandler.sessionTask = sessionTask;
        [task.responseHandlers addObject:responseHandler];
        if (self.queue) {
            [self.queue enqueue:sessionTask];
            return;
        }
        [sessionTask resume];
    });
}
- (void)addResponseHandler:(BKHttpResponseHandler *)responseHandler{
    dispatch_sync(self.taskQueue, ^{
       BKHttpRequestTask *task = [_pool valueForKey:responseHandler.taskId];

        responseHandler.sessionTask = task.sessionTask;
        [task.responseHandlers addObject:responseHandler];
    });
}
- (void)removeTaskWithTaskId:(NSString *)taskId{
    BKHttpRequestTask *task = [_pool valueForKey:taskId];
    [_pool removeObjectForKey:taskId];
    // 从队列中移除
    if (self.queue) {
        [self.queue cancel:task.sessionTask];
        return;
    }
    [task.sessionTask cancel];
}
- (void)removeResponseHandler:(BKHttpResponseHandler *)responseHandler{
    dispatch_sync(self.taskQueue, ^{
       BKHttpRequestTask *task = [_pool valueForKey:responseHandler.taskId];
        if (task) {
            if ([task.responseHandlers containsObject:responseHandler]) {
                [task.responseHandlers removeObject:responseHandler];
            }
            if (task.responseHandlers.count == 0) {
                [self removeTaskWithTaskId:task.taskId];
            }
        }
    });
}
- (NSURLSessionTask *)sessionTaskForTaskId:(NSString *)taskId{
    __block NSURLSessionTask *task = nil;
    dispatch_sync(self.taskQueue, ^{
        task = [_pool objectForKey:taskId];
    });
    return task;
}
- (void)clearTaskWithTaskId:(NSString *)taskId{
    [_pool removeObjectForKey:taskId];
    if (self.queue) {
        [self.queue sessionTaskFinished:nil];
    }
}
- (void)clearTaskWithTaskId:(NSString *_Nonnull)taskId runWithBlock:(nullable void(^)(BKHttpResponseHandler *_Nonnull)) block{
    dispatch_sync(self.taskQueue, ^{
        BKHttpRequestTask *item = [_pool valueForKey:taskId];
        if (item) {
            for (NSInteger i = 0; i < item.responseHandlers.count; i++) {
                BKHttpResponseHandler *responseHandler = [item.responseHandlers objectAtIndex:i];
                dispatch_async(dispatch_get_main_queue(),^{
                    block(responseHandler);
                });
            }
            [self clearTaskWithTaskId:taskId];
        }
    });
}


@end

@implementation BKHttpResponseHandler
- (id _Nonnull)initWithTaskId:(NSString *)taskId UUID:(NSUUID *)uuid{
    if (self = [super init]) {
        self.uuid = uuid;
        self.taskId = taskId;
    }
    return self;
}
@end

@interface BKHttpRequestQueue()

@property (nonatomic, strong) NSMutableArray *_Nonnull tasks;
@property (nonatomic, strong) dispatch_queue_t syncQueue;
@end
@implementation BKHttpRequestQueue
- (id)init{
    if (self = [super init]) {
        self.tasks = [NSMutableArray array];
        self.maxConcurrentTaskCount = 5;
        NSString *queueName = [NSString stringWithFormat:@"%@-HttpRequest-Queue-%@", APP_ID, [[NSUUID UUID] UUIDString]];
        self.syncQueue = dispatch_queue_create([queueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_SERIAL);
    }
    return self;
}

- (void)startNext{
    dispatch_sync(self.syncQueue, ^{
        while ( self.activeTaskCount < self.maxConcurrentTaskCount){
            NSURLSessionTask *task = [self dequeue];
            if (!task) {
                return;
            }
            [task resume];
            ++self.activeTaskCount;
        }
    });
}
- (void)enqueue:(NSURLSessionTask *)task{
    [self.tasks addObject:task];
//    [task addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
    [self startNext];
}
- (NSURLSessionTask *)dequeue{
    if ([self.tasks count] == 0) {
        return nil;
    }
    NSURLSessionTask *task = self.tasks.firstObject;
    [self.tasks removeObject:task];
    return task;
}
- (void)cancel:(NSURLSessionTask *)task{
    dispatch_sync(self.syncQueue, ^{
        if (task.state == NSURLSessionTaskStateSuspended) {
            [task cancel];
            [self.tasks removeObject:task];
        }
    });
}
- (void)sessionTaskFinished:(NSURLSessionTask * _Nullable)task{
    dispatch_sync(self.syncQueue, ^{
        --self.activeTaskCount;
    });
    [self startNext];
}
//- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
//    if ([object isKindOfClass:[NSURLSessionTask class]] && [keyPath isEqualToString:@"state"]) {
//        NSURLSessionTask *sessionTask = (NSURLSessionTask *)object;
//        if (sessionTask.state == NSURLSessionTaskStateCanceling || sessionTask.state == NSURLSessionTaskStateCompleted){
//            dispatch_sync(self.queue, ^{
//                --self.activeTaskCount;
//            });
//            [self startNext];
//            [sessionTask removeObserver:self forKeyPath:@"state"];
//        }
//    }
//}
@end

